package de.hauschild.gmltracer.gml;

import java.util.EmptyStackException;
import java.util.Stack;

/**
 * The token stack used as runtime memory of a GML program.
 * 
 * @author Klaus Hauschild
 * @since 1.0.0
 */
public class TokenStack {

  private final Stack<Token> stack;

  /**
   * Creates a empty token stack.
   */
  public TokenStack() {
    this(new Stack<Token>());
  }

  /**
   * Creates a new token stack using the given 'raw' data.
   * 
   * @param theStack
   */
  public TokenStack(final Stack<Token> theStack) {
    stack = theStack;
  }

  /**
   * Pops the top token from the stack. If the expected type is not assignable
   * from the top tokens type a {@link IllegalArgumentException} will be thrown.
   * If the stack is empty a {@link EmptyStackException} will be thrown.
   * 
   * @param <T>
   *          the type of the token
   * @param expectedType
   *          the expected type of the token.
   * 
   * @return the top token
   */
  @SuppressWarnings("unchecked")
  public <T extends Token> T pop(final Class<T> expectedType) {
    final Token top = stack.peek();
    if (top == null) {
      throw new EmptyStackException();
    }
    if (expectedType.isAssignableFrom(top.getClass())) {
      return (T) stack.pop();
    }
    throw new IllegalArgumentException(String.format("The token (%s) has not the expected type (%s).", top, //$NON-NLS-1$
        expectedType));
  }

  /**
   * Push the token to the stack.
   * 
   * @param token
   *          the token
   */
  public void push(final Token token) {
    stack.push(token);
  }

  @Override
  public String toString() {
    return stack.toString();
  }
}
